<!-- eslint-disable vue/prop-name-casing -->
<script>
import jsonCodeMirror from '@/components/JavascriptCodemirror/index.vue'
import { uploadFile } from '@/api/tool'
import { searchGlobalSettings } from '@/api/globalSetting'

export default {
  components: {
    json_code: jsonCodeMirror
  },
  props: {
    sub_task_arg: {
      type: Object,
      required: true,
      default: null
    },
    arg_key: {
      type: Number,
      required: true,
      default: null
    },
    memory_bus: {
      type: Object,
      required: true,
      default: null
    }
  },
  data() {
    return {
      finalValue: '',
      inputTypeOptions: [
        { value: 'editBox', label: 'Edit Box' },
        { value: 'singleSelect', label: 'Single Select' },
        { value: 'multiSelect', label: 'Multi Select' }
      ],
      selectedInputType: 'editBox',
      singleSelectOptions: [
        { value: '10', label: 'Option 1' },
        { value: '20', label: 'Option 2' }
      ],
      selectedSingleOption: null,
      multiSelectOptions: [
        { value: '100', label: 'Option A' },
        { value: '200', label: 'Option B' }
      ],
      selectedMultiOptions: [],
      noNeedConfirm: false, // 自动装填参数时，不需要确认
      dontUpdate: false, // 自动装填参数时，不要自动更新
      /* 上传文件相关 */
      fileList: [],
      /* 填入信息相关 */
      firstLevelLabel: [],
      firstLevelValue: -1,
      inputEditModel: '',
      secondLevelLabel: [],
      secondLevelValue: '',
      secondLevelSavedData: [], // 选择refer或者profile时，需要保存它们json的key和value来获取value（Label中只存了key）
      /* json选择相关 */
      isJsonObject: false,
      JsonLevel: 0,
      JsonContentSelectLabel: [],
      JsonContentSelectValue: [],
      JsonContentSavedValue: {},
      /* 保留字段 */
      typeSelect: [],
      typeSelectValue: '',
      /* codemirror代码 */
      inputChangeCancel: 0,
      jsonCode: '{\n' +
        '\t"variableName": "xxxx",              \n' +
        '\t"prompt": "xxxx",              \n' +
        '\t"defaultValue": "xxxx",    \n' +
        '\t"inputMode": "singleLine"      \n' +
        '}\n'
    }
  },
  watch: {
    sub_task_arg: {
      deep: true,
      handler(val) {
        // 加载数据进入 Const
        if ('value' in val && this.inputEditModel === '') {
          this.inputEditModel = val.value
        }
      }
    },
    memory_bus: {
      deep: true,
      handler(val) {
        this.getSelectorContent(val)
        // 尝试自动加载
        this.attemptAutoChoose()
      }
    },
    selectedInputType(newVal, oldVal) {
      if (this.noNeedConfirm) {
        // console.log('跳过检测')
        this.noNeedConfirm = false
        return
      }
      if (this.inputChangeCancel === 0) {
        if (oldVal !== newVal) {
          this.confirmChange(newVal, oldVal)
        }
      } else if (this.firstLevelValue === -1 && this.inputChangeCancel === 1) {
        if (oldVal !== newVal) {
          this.confirmChange(newVal, oldVal)
        }
        this.inputChangeCancel = 0
      } else {
        this.inputChangeCancel = 0
      }
      // this.updateCodeHint(newVal)
    },
    firstLevelValue(newVal, oldVal) {
      if (this.dontUpdate) {
        // watch函数 在自动装填参数函数的后面执行，会影响实际的装填值
        this.dontUpdate = false
        return
      } else {
        this.$confirm(this.$t('input_change_tips'), this.$t('tip'), {
          confirmButtonText: this.$t('confirm'),
          cancelButtonText: this.$t('cancel'),
          type: 'warning',
          closeOnClickModal: false
        }).then(() => {
          // 切换后更新 jsonCode
          this.updateFileCodeHint(newVal)
          // 手动聚焦到 ref 为 ref="jsonCodeEditor" 的组件上
          this.$nextTick(() => {
            if (this.$refs.jsonCodeEditor) {
              this.$refs.jsonCodeEditor.focus()
            }
          })
        }).catch(error => {
          console.log(error)
          this.firstLevelValue = oldVal // 恢复默认值
          this.dontUpdate = true
          this.$message({
            message: this.$t('cancel'),
            type: 'info'
          })
        })
      }
    }
  },
  mounted() {
    // 初始化所有 memory_bus 的可选项
    this.getSelectorContent(this.memory_bus)
  },
  methods: {
    confirmChange(newVal, oldVal) {
      this.$confirm(this.$t('input_change_tips'), this.$t('tip'), {
        confirmButtonText: this.$t('confirm'),
        cancelButtonText: this.$t('cancel'),
        type: 'warning',
        closeOnClickModal: false
      }).then(() => {
        // 切换后更新 jsonCode
        this.updateCodeHint(this.selectedInputType)
      }).catch(error => {
        console.log(error)
        this.inputChangeCancel = 2
        this.selectedInputType = oldVal // 恢复默认值
        this.$message({
          message: this.$t('cancel'),
          type: 'info'
        })
      })
    },
    updateCodeHint(inputType) {
      let hint = ''
      switch (inputType) {
        case 'editBox':
          hint = `{
	"variableName": "xxxx",
	"prompt": "xxxx",
	"defaultValue": "xxxx",
	"inputMode": "singleLine"
}`
          break
        case 'singleSelect':
          hint = `{
  "variableName": "xxxx",
	"prompt": "xxxx",
  "defaultValue": "xxxx",
	"options": [
		{
			"name": "xxxx",
			"value": "xxxx",
			"checked": "true"
		},
		{
			"name": "xxxx",
			"value": "xxxx",
			"checked": "false"
		}
	]
}`
          break
        case 'multiSelect':
          hint = `{
  "variableName": "xxxx",
	"prompt": "xxxx",
  "defaultValue": "xxxx",
	"options": [
		{
			"name": "xxxx",
			"value": "xxxx"
		},
		{
			"name": "xxxx",
			"value": "xxxx"
		}
	]
}`
          break
      }
      this.jsonCode = hint
    },
    updateFileCodeHint(newVal) {
      let hint = ''
      switch (newVal) {
        case -3:
          hint = `{
  "variableName": "xxxx",
  "prompt": "xxxx",
  "fileSizeLimit": "431243",
  "fileSizeExtension": "png,jpg,gif"
}`
          break
        default:
          hint = `{
  "variableName": "xxxx",
	"prompt": "xxxx",
	"defaultValue": "xxxx",
	"inputMode": "singleLine"
}`
      }
      this.jsonCode = hint
    },
    initSelectorContent() {
      // 添加file作为一种输入方式
      this.firstLevelLabel.push({
        'value': -3,
        'label': 'file'
      })
      // 添加const作为一种输入方式
      this.firstLevelLabel.push({
        'value': -2,
        'label': 'const'
      })
      // 添加input作为一种输入方式
      this.firstLevelLabel.push({
        'value': -1,
        'label': 'input'
      })
    },
    getSelectorContent(memoryBus) {
      this.firstLevelLabel = []
      this.secondLevelLabel = []
      this.initSelectorContent()
      /** 注意这里需要-3是因为第一级 选单中默认填入了三种Label -1: input, -2: const, -3: file */
      let index = this.firstLevelLabel.length - 3
      Object.keys(memoryBus).forEach((key) => {
        // 将MemoryBus的每一个键值对添加进selector中
        this.firstLevelLabel.push({
          'value': index++,
          'label': key
        })
        // 保存其值的json信息
        this.secondLevelSavedData.push(memoryBus[key])
        // 完善每一个selector中option的值
        const optionList = []
        Object.keys(memoryBus[key]).forEach((key2) => {
          optionList.push({
            'label': key2,
            'value': key2
          })
        })
        this.secondLevelLabel.push(optionList)
      })
    },
    // 触发 memoryBus 刷新的函数
    handleFirstSelectorFocus() {
      this.$emit('refresh_memory_bus')
    },
    // 重置已选择的参数
    resetArgument() {
      this.firstLevelValue = -2
      this.clearSecondSelect()
    },
    // 确认填入，将参数发送到父组件中
    selectArg() {
      let data
      if (this.firstLevelValue >= 0) {
        data = this.secondLevelSavedData[this.firstLevelValue][this.secondLevelValue]
        // 接着，清理json相关的selector
        this.isJsonObject = false
        this.JsonContentSelectValue = []
        this.JsonContentSelectLabel = []
        // 判断是否为json对象，是则启动json相关的选择
        if (data instanceof Object) {
          this.isJsonObject = true // 开启Json选择
          this.JsonLevel = 0 // 初始化JsonLevel
          this.JsonContentSavedValue = data // 暂存json对象
          // 初始化第一层选择器
          const selector = []
          Object.keys(this.JsonContentSavedValue).forEach((key) => {
            selector.push({
              'label': key,
              'value': key
            })
          })
          this.JsonContentSelectLabel.push(selector)
          this.JsonContentSelectValue.push('')
        }
      }
    },
    clearSecondSelect() {
      this.inputChangeCancel = 1
      this.selectedInputType = 'editBox'
      this.secondLevelValue = ''
      // 清理json相关的selector
      this.isJsonObject = false
      this.JsonContentSelectValue = []
      this.JsonContentSelectLabel = []
    },
    // 监听Json结构的选择器
    jsonSelectWatcher(level) {
      // console.log('监听器触发，层数：' + level)
      // 清理i + 1 ~ nowLen之间的内容
      this.JsonContentSelectLabel = this.JsonContentSelectLabel.slice(0, level + 1)
      this.JsonContentSelectValue = this.JsonContentSelectValue.slice(0, level + 1)
      // 接着选择出内容, 并绑定到父组件arg上
      let data = this.JsonContentSavedValue
      for (let i = 0; i <= level; i++) {
        // 层层选择
        data = data[this.JsonContentSelectValue[i]]
      }
      // 判断data是否仍是json，是则增加层数
      if (data instanceof Object) {
        // 添加选择器
        const selector = []
        Object.keys(data).forEach((key) => {
          selector.push({
            'label': key,
            'value': key
          })
        })
        this.JsonContentSelectLabel.push(selector)
        this.JsonContentSelectValue.push('')
      }
    },
    // 向父组件返回每个参数的选择信息
    getArgInfo() {
      // parameters 的结构包括: name sourceType sourceData{type option}

      // 当自动填充还未进行时，简单地返回脚本内的参数内容
      // console.log('getArgInfo, param', this.sub_task_arg)
      if (!('value' in this.sub_task_arg)) {
        return this.sub_task_arg
      }
      // 否则，根据前端选择的参数，返回对应的参数信息
      const info = {
        'name': this.sub_task_arg.name
      }
      let sourceType = ''
      const sourceData = {
        'type': '',
        'option': {}
      }

      if (this.firstLevelValue === -2) {
        // 选择为 Const
        sourceType = 'const'
        sourceData.type = 'default'
        sourceData.option = {
          'defaultValue': this.inputEditModel
        }
      } else if (this.firstLevelValue === -1) {
        // input 类型
        sourceType = 'input'
        try {
          const jsonObj = JSON.parse(this.jsonCode)
          sourceData.type = this.selectedInputType
          sourceData.option = jsonObj
        } catch (error) {
          console.error('Error parsing jsonCode:', error)
          this.$message.error('JSON 格式有误')
        }
      } else if (this.firstLevelValue === -3) {
        // file 类型
        try {
          const jsonObj = JSON.parse(this.jsonCode)
          sourceType = 'file'
          sourceData.type = 'default'
          sourceData.option = jsonObj
        } catch (error) {
          console.error('Error parsing jsonCode:', error)
          this.$message.error('JSON 格式有误')
        }
      } else if (this.firstLevelLabel[this.firstLevelValue + 3].label === 'profiles') {
        // profile 类型
        sourceType = 'refer'
        sourceData.type = 'default'
        sourceData.option = {
          'defaultValue': 'profile' + this.secondLevelValue
        }
      } else {
        // refer类型
        sourceType = 'refer'
        // 设定基本位置属性
        let pos = this.firstLevelLabel[this.firstLevelValue + 3].label + '.' + this.secondLevelValue
        // 如果解析的json,那么获取这个解析的路径并依次加入pos
        if (this.isJsonObject) {
          for (const key in this.JsonContentSelectLabel) {
            pos += '.' + this.JsonContentSelectValue[key]
          }
        }
        sourceData.type = 'default'
        sourceData.option = {
          'defaultValue': pos
        }
      }
      info['sourceType'] = sourceType
      info['sourceData'] = sourceData
      return info
    },
    // 上传文件的请求发送函数
    uploadFile(param) {
      const formData = new FormData()
      formData.append('file', param.file)
      uploadFile(formData).then(response => {
        console.log('上传文件成功', response)
        // 保存二进制格式的文件
        this.$emit('save-file', response)
        // 文件图标设为绿色
        param.onSuccess()
      }).catch(error => {
        console.log('上传文件失败', error)
        param.onError()
      })
    },
    // 移除上传文件的处理函数
    beforeRemoveFile(file, fileList) {
      return this.$confirm(`确定移除${file.name}?`)
    },
    // 上传文件个数超过限制的处理函数
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`)
    },
    // 提供给父组件的接口，能够自动选择对应的值
    autoChooseValue(path) {
      // console.log('触发自动选择，memoryBus 为', this.memory_bus)
      // 清空选择器
      this.firstLevelValue = -1
      this.inputEditModel = ''
      this.secondLevelValue = ''
      this.isJsonObject = false
      // 自动装填数据
      if (path.sourceType === 'input') {
        const inputContent = path.sourceData
        if (inputContent.type !== 'editBox') {
          // 需要无提示地变换一次 input 类型
          this.noNeedConfirm = true
        }
        // 选择二级
        this.selectedInputType = inputContent.type
        // 填写 json
        // console.log('自动装填 input', inputContent.option, this.jsonCode)
        this.jsonCode = JSON.stringify(inputContent.option, null, 4)
      } else if (path.sourceType === 'const') {
        // 解析 Const 类型
        // this.argumentConst = true
        this.dontUpdate = true
        this.firstLevelValue = -2
        this.inputEditModel = path.sourceData.option.defaultValue
      } else if (path.sourceType === 'refer') {
        const referPath = path.sourceData.option.defaultValue
        const jsonPath = referPath.split('.')
        // 第一级
        this.dontUpdate = true
        for (const key in this.firstLevelLabel) {
          if (this.firstLevelLabel[key].label === jsonPath[0]) {
            this.firstLevelValue = this.firstLevelLabel[key].value
          }
        }
        // 第二级
        this.secondLevelValue = jsonPath[1]
        // 开启json选择
        this.isJsonObject = true // 开启Json选择
        this.JsonLevel = 0 // 初始化JsonLevel
        this.JsonContentSavedValue = this.memory_bus[jsonPath[0]][jsonPath[1]] // 暂存json对象
        // console.log('get json object', this.JsonContentSavedValue)
        // 初始化第一层选择器
        const selector = []
        Object.keys(this.JsonContentSavedValue).forEach((key) => {
          selector.push({
            'label': key,
            'value': key
          })
        })
        this.JsonContentSelectLabel.push(selector)
        this.JsonContentSelectValue.push('')
        // 剩余的选择
        for (const key in jsonPath) {
          if (key !== 0 && key !== 1) {
            this.JsonContentSelectValue[key - 2] = jsonPath[key]
            this.jsonSelectWatcher(key - 2)
          }
        }
      } else if (path.sourceType === 'file') {
        const inputContent = path.sourceData
        // 填写 json
        this.dontUpdate = true
        // 选择文件
        this.firstLevelValue = -3 // 设置为文件
        // console.log('自动装填 input', inputContent.option, this.jsonCode)
        this.jsonCode = JSON.stringify(inputContent.option, null, 4)
      }
      this.$emit('format_argument', this.arg_key)
    },
    // taskEdit 获取到 memoryBus 后再调用自动选择
    attemptAutoChoose() {
      if ('sourceType' in this.sub_task_arg) {
        // console.log('触发一个自动选择', this.sub_task_arg, this.memory_bus)
        this.autoChooseValue(this.sub_task_arg)
      }
    },
    // 点击查看输入参数帮助弹出的浮层窗口
    async openInputHelp() {
      /* 获取输入参数的帮助内容 */
      let defaultContent = '获取输入参数配置的帮助时出错'
      await searchGlobalSettings({ 'searchVal': '', 'region': 'input_help' })
        .then(res => {
          defaultContent = res[0]['value']
        })
        .catch(err => {
          console.log('获取输入参数配置的帮助时出错：', err)
        })

      /* 给消息框添加样式 */
      const style = document.createElement('style')
      style.textContent = `
        .custom-alert-width {
          width: 1000px !important;
        }`
      document.head.appendChild(style)

      /* 输入参数帮助弹出 */
      this.$alert(`<textarea readonly style="width: 100%; min-height: 280px; border: none; background-color: #f0f0f0; overflow-y: auto;">${defaultContent}</textarea>`, '帮助', {
        confirmButtonText: '关闭',
        center: true,
        dangerouslyUseHTMLString: true,
        customClass: 'custom-alert-width'
      })
    }
  }
}
</script>

<template>
  <!-- 展示json部分 -->
  <div>
    <!-- json展示框 -->
    <div class="json-show">
      <json-viewer :value="sub_task_arg" />
    </div>
    <!-- 属性选择与修改栏 -->
    <div class="json-filler">
      <el-row :gutter="6" type="flex" align="middle">
        <!-- 第一级选择器 -->
        <el-col :span="4">
          <el-select v-model="firstLevelValue" filterable :placeholder="$t('pleaseSelect')" @focus="handleFirstSelectorFocus" @change="clearSecondSelect">
            <el-option
              v-for="item in firstLevelLabel"
              :key="'props' + item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-col>
        <!-- 当选择的是input时,为一个输入框,当选择的是文件的时候,隐藏这一列,否则是一个选框 -->
        <el-col v-if="firstLevelValue !== -3" :span="4">
          <div v-if="firstLevelValue === -1">
            <el-select v-model="selectedInputType" placeholder="手动填充数据">
              <el-option
                v-for="item in inputTypeOptions"
                :key="'object' + item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </div>
          <div v-else-if="firstLevelValue === -2">
            <el-input v-model="inputEditModel" placeholder="手动填充数据" />
          </div>
          <!-- 选择器选择后 直接把值绑定到arg上 -->
          <el-select v-else v-model="secondLevelValue" filterable placeholder="选择键值" @change="selectArg">
            <el-option
              v-for="item in secondLevelLabel[firstLevelValue]"
              :key="'object' + item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-col>
        <!-- 为了选择json数据结构，需要一层一层的添加选择框 -->
        <el-col v-for="(item, index) in JsonContentSelectLabel" :key="index" :span="4">
          <el-select v-model="JsonContentSelectValue[index]" placeholder="请选择属性" @change="jsonSelectWatcher(index)">
            <el-option
              v-for="folks in item"
              :key="'json' + index + folks.value"
              :label="folks.label"
              :value="folks.value"
            />
          </el-select>
        </el-col>
        <!-- 输入参数的帮助浮层按钮 -->
        <el-col>
          <el-button type="text" class="help-btn" @click="openInputHelp">帮助[输入参数配置]</el-button>
        </el-col>
      </el-row>
      <!-- 上传文件区域 -->
      <!--el-row v-if="firstLevelValue === -3">
        <el-upload
          :http-request="uploadFile"
          :before-remove="beforeRemoveFile"
          drag
          :limit="1"
          :on-exceed="handleExceed"
          :first-list="fileList"
          style="margin-top: 15px"
        >
          <i class="el-icon-upload" />
          <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        </el-upload>
      </!--el-row-->
    </div>
    <!--    配置input的codemirror-->
    <div v-if="firstLevelValue === -1 || firstLevelValue === -3">
      <!--python_code v-model="jsonCode" /-->
      <json_code ref="jsonCodeEditor" v-model="jsonCode" />
    </div>
  </div>
</template>

<style scoped>
.json-filler{
  margin-top: 10px;
  margin-bottom: 15px;
}
.help-btn {
  margin-left: 10px;
}
</style>
